#include "../../head/mainHead.h"

// 高优先级优先（剥夺式）

void phpf(){
    system("cls");
    //构建到达时间队列
    queueInit();
    //将到达时间转化为分钟格式
    arrStrsToMin();

    printf("+-----------------------------------------------------+\n"); 
    printf("|-------------进------程-------开------始-------------|\n"); 
    printf("+-----------------------------------------------------+\n");

    boolean isProSel[5] = {0};  //记录进程是否执行完毕
    int curTime = arriveTime[queue[1]];      //将第一个进程到达时间设置为初始时间
    startTime[queue[1]] = curTime;
    int left = 1;       //queue下标：最先未被执行完的进程
    int right = 1;      //queue下标：已到达程序中最新到达的进程
    while(left <= right){
        //在已经到达的程序中选取优先级最高的进程
        int index = left;
        for(int j = left ; j <= right; j++){
            if(!isProSel[j] && p[queue[index]].Priority < p[queue[j]].Priority){
                index = j;
            }
        }
        if(!breakTime[queue[index]]){       //初始化当前选中进程的开始时间
            breakTime[queue[index]] = curTime;
            startTime[queue[index]] = curTime;
        }
        boolean isBreakFlag = 0;    //是否发生了中断
        // 预估结束时间 = 当前时间 + (进程运行总时间 - (最近一次中断时间 - 开始时间)) 
        //因为随着时间的推进会有高优先级的进程发生抢占，产生中断 
        int estiEndTime = curTime + (p[queue[index]].Tr - (breakTime[queue[index]] - startTime[queue[index]]));
        for(int j = right + 1; j < 5; j++){

            if(estiEndTime <= arriveTime[queue[j]]){
                if(estiEndTime == arriveTime[queue[j]]){
                    right++;
                }
                break; //在当前进程执行完前没有新的进程到达
            }else{
                right++;
                if(p[queue[index]].Priority > p[queue[j]].Priority){
                    continue; //新到达的进程的优先级小于当前正在执行的进程
                }else{
                    //如果执行过程中遇到优先级更高的则中断，
                    //并且更新当前时间和该进程的中断时间
                    isBreakFlag = 1;
                    curTime = arriveTime[queue[j]];
                    breakTime[queue[index]] = curTime;
                    break;
                }
            }
        }

        if(isBreakFlag){
            //表示发生了抢占
        }else{      // 没有发生中断就执行完毕
            isProSel[queue[index]] = 1;
            curTime = estiEndTime;
            endTime[queue[index]] = curTime;
            while(isProSel[left]){//缩小滑动窗口
                left++;
            }
        }

        printf("|--->选择进程 %s\tisProSel[%d] = %d\t\n",p[queue[index]].PNAME,queue[index],isProSel[queue[index]]);
        // printf("left = %d\tright = %d\n",left,right);

    }
    printf("+-----------------------------------------------------+\n");

    // 输出进程到达时间
    taPrint();
    // 将开始时间分钟格式转化为时分格式
    startMinToStrs();
    // 输出开始时间
    // tsPrint();
    // 进程运行时间
    trPrint();
    // 将结束时间分钟格式转化为时分格式
    endMinToStrs();
    // 输出结束时间
    tfPrint();

    // 计算周转时间
    calcuTar();
    // 计算带权周转时间
    calcuTTWA();
    // 输出进程周转时间
    cycleTime();
    // 输出带权周转时间
    cycleTimeWithRight();
    // 输出平均周转时间
    avgCycleTime();
    // 输出平均带权周转时间
    avgCycleTimeWithRight();
}